package com.irenty.effectivej.ch02.objectreation;

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.logging.Logger;

import org.testng.annotations.Test;

/*
 * Item 5: CREATING AND DESTROYING OBJECTS Avoid creating unnecessary objects
 */
public class AvoidUnnecessaryObjects {
	private final static Logger LOGGER = Logger
			.getLogger(AvoidUnnecessaryObjects.class.getName());

	@Test
	public void testStringCreation() throws Exception {
		String s1 = new String("lala"); // DON'T DO THIS! 2 ojbects !
		String s2 = "stringette"; // good! only one object
	}

	@Test
	public void testBooleanCreation() throws Exception {
		Boolean b1 = new Boolean("true"); // DON'T DO THIS! always creates a new
											// object!
		Boolean b2 = Boolean.valueOf("true"); // good! static factory method
												// always returns same object
	}

	/*
	 * unnecessarily creates a new Calendar, TimeZone and two Date instances
	 * each time it is invoked.
	 */
	private static class Person1 {
		private final Date birthDate;

		public Person1(Date birthDate) {
			this.birthDate = birthDate;
		}

		// DON'T DO THIS!
		public boolean isBabyBoomer() {
			// Unnecessary allocation of expensive object
			Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
			gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
			Date boomStart = gmtCal.getTime();
			gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
			Date boomEnd = gmtCal.getTime();
			return birthDate.compareTo(boomStart) >= 0
					&& birthDate.compareTo(boomEnd) < 0;
		}
	}

	@Test
	public void testPerson1Creation() throws Exception {
		Person1 p1 = new Person1(new Date());
		LOGGER.info("Person1 is baby boomer = " + p1.isBabyBoomer());
	}

	/*
	 * 250 times faster
	 */
	private static class Person2 {
		private final Date birthDate;

		public Person2(Date birthDate) {
			this.birthDate = birthDate;
		}

		/**
		 * The starting and ending dates of the baby boom.
		 */
		private static final Date BOOM_START;
		private static final Date BOOM_END;
		static {
			Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
			gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
			BOOM_START = gmtCal.getTime();
			gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
			BOOM_END = gmtCal.getTime();
		}

		public boolean isBabyBoomer() {
			return birthDate.compareTo(BOOM_START) >= 0
					&& birthDate.compareTo(BOOM_END) < 0;
		}
	}

	@Test
	public void testPerson2Creation() throws Exception {
		Person2 p2 = new Person2(new Date());
		LOGGER.info("Person2 is baby boomer = " + p2.isBabyBoomer());
	}

	@Test
	/*
	 *  very slow - each time new Long object is created
	 */
	public void testAutoboxing() throws Exception {
		long started = System.currentTimeMillis();
		Long sum = 0L;
		for (long i = 0; i < Integer.MAX_VALUE / 10; i++) {
			sum += i;
		}
		LOGGER.info(sum.toString() + " calculated after: " + (System.currentTimeMillis() - started) + " miliseconds");
	}
	
	@Test
	/*
	 * prefer primitives to boxed primitives, and watch out for unintentional autoboxing
	 * over 10 x faster
	 */
	public void testPrimitives() throws Exception {
		long started = System.currentTimeMillis();
		long sum = 0L;
		for (long i = 0; i < Integer.MAX_VALUE / 10; i++) {
			sum += i;
		}
		LOGGER.info(sum + " calculated after: " + (System.currentTimeMillis() - started) + " miliseconds");
	}

}
